package com.whosly.mysql.protocol.packet.jdbc;

import com.whosly.mysql.protocol.packet.IMySQLPacket;
import com.whosly.mysql.protocol.packet.MysqlPackConstants;
import com.whosly.mysql.protocol.packet.impl.BinaryPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @author fengyang
 * @date 2023/7/20 上午10:24
 * @see <a href="yueny09@163.com">mailTo: yueny09@163.com</a>
 */
public abstract class MySQLPacket implements IMySQLPacket
{
    public static final byte PACKET_OK = 0x00;
    public static final byte PACKET_ERROR = (byte) 0xff;
    public static final byte PACKET_EOF = (byte) 0xfe;
    public static final byte PACKET_LOCAL_INFILE = (byte) 0xfb;

    /**
     * NULL is sent as 0xfb
     */
    public static final byte NULL_MARK = (byte) 0xfb;

    public static final byte[] FILLER1 = new byte[0];
    public static final byte[] FILLER2 = new byte[2];
    public static final byte[] FILLER_10 = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    public static final byte[] FILLER_11 = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    public static final byte[] FILLER_13 = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    /**
     * String 转  bytes
     */
    public static byte[] parseBytes(String value)
    {
        if (value == null) {
            return null;
        }

        return parseBytes(value, StandardCharsets.UTF_8);
    }

    /**
     * String 转  bytes
     */
    public static byte[] parseBytes(String value, String charsetName)
    {
        if (value == null) {
            return null;
        }

        return value.getBytes(Charset.forName(charsetName));
    }

    /**
     * String 转  bytes
     */
    public static byte[] parseBytes(String value, Charset encoding)
    {
        if (value == null) {
            return null;
        }
        return value.getBytes(encoding);
    }

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 数据的长度. 不包含头
     */
    @Getter
    private int packetLength;

    @Getter
    @Setter
    private byte packId = 1;

    public final void setArgs(int packetLength, byte packId) {
        this.packetLength = packetLength;
        this.packId = packId;
    }

    /**
     * 组装整个数据包需要的buffer大小，按此大小申请空间可以避免浪费或扩容
     * 由于result等场合根据具体值不同编码长度不同，此方法返回的长度仅供参考不一定完全准确
     * @return
     */
    public int calcBufferSize() {
        return getHeaderSize() + calcPacketSize();
    }

    /**
     * 组装Packet 需要的计算数据包大小
     * 由于result等场合根据具体值不同编码长度不同，此方法返回的长度仅供参考不一定完全准确
     */
    public abstract int calcPacketSize();

    /**
     * 头数据包大小
     */
    protected final int getHeaderSize() {
        return MysqlPackConstants.HEADER_SIZE;
    }

    /**
     * 取得数据包信息
     */
    public String getPacketInfo() {
        return this.getClass().getSimpleName();
    }

    @Override
    public ByteBuf writeBuf()
    {
        return writeBuf(Unpooled.buffer(calcBufferSize()));
    }

    @Override
    public final void read(BinaryPacket bin)
    {
        setArgs(bin.getPacketLength(), bin.getPackId());

        read(bin.getData());
    }

    @Override
    public String toString() {
        return getPacketInfo() + ToStringBuilder.reflectionToString(this,
                ToStringStyle.SHORT_PREFIX_STYLE);
    }

}
